﻿//-----------------------------------------------------------------------
// <copyright file="PathSuggestionContext.cs" author="Artak Mkrtchyan">
//     Creative Commons - GNU General Public License (http://creativecommons.org/licenses/GPL/2.0/
// </copyright>
// <author>Artak Mkrtchyan</author>
// <email>mkArtak@gmail.com</email>
// <date>10/02/2013</date>
//-----------------------------------------------------------------------

using ConsoleHoster.Common.Utilities;
using System;
using System.IO;
using System.Text.RegularExpressions;

namespace ConsoleHoster.Model.Suggestions
{
	internal sealed class PathSuggestionContext : IPathSuggestionContext
	{
		private readonly IPathSuggestionProvider suggestionProvider;

		private string lastProvidedSuggestion = null;
		private string folder = null;
		private string pattern = null;
		private bool isUpdated = false;
		private string suggestionBase = null;
		private bool suggestFoldersOnly = false;

		public PathSuggestionContext(IPathSuggestionProvider argSuggestionProvider)
		{
			if (argSuggestionProvider == null)
			{
				throw new ArgumentNullException("argSuggestionProvider");
			}

			this.suggestionProvider = argSuggestionProvider;
		}

		public bool UpdateContext(string argCommand, string argCurrentFolder)
		{
			ValidationManager.RequireArgumentNotNull(argCurrentFolder, "argCurrentFolder");
			
			bool tmpResult = false;

			string tmpFolder = null;
			string tmpPattern = null;
			if (!this.IsUpdated)
			{
				string tmpRegexPattern = @"((?:(?:(^\w:|\s\w:)|\.\.?)(?:\/|\\))?(?:(?:[-$()\w\{\}.]+(?:[-$()\w\{\}.]+)?)(?:\/|\\))*)([-$()\w\{\}\.]*)\t";
				Match tmpRegexMatch = Regex.Match(argCommand, tmpRegexPattern);
				if (tmpRegexMatch.Success)
				{
					if (tmpRegexMatch.Groups[2].Success)
					{
						//Drive letter specified
						tmpFolder = tmpRegexMatch.Groups[1].Value.Trim();
					}
					else
					{
						// Relative Path specified
						tmpFolder = Path.Combine(argCurrentFolder, tmpRegexMatch.Groups[1].Value);
					}

					tmpPattern = tmpRegexMatch.Groups[3].Value;

					int tmpSuggestionBaseStartIndex = tmpRegexMatch.Index;
					int tmpSuggestionBaseStartIndexEndIndex = tmpRegexMatch.Groups[3].Index;
					this.suggestionBase = (tmpSuggestionBaseStartIndex == tmpSuggestionBaseStartIndexEndIndex) ? String.Empty : argCommand.Substring(tmpSuggestionBaseStartIndex, tmpSuggestionBaseStartIndexEndIndex - tmpSuggestionBaseStartIndex);

					this.SuggestFoldersOnly = argCommand == "cd " + tmpRegexMatch.Value;
					this.PrepareSuggestionsIfRequired(tmpFolder, tmpPattern);

					this.IsUpdated = true;
					tmpResult = true;
				}
			}
			else
			{
				tmpResult = true;
			}

			return tmpResult;
		}

		public void Reset()
		{
			this.Folder = null;
			this.LastProvidedSuggestion = null;
			this.Pattern = null;
			this.IsUpdated = false;
			this.SuggestFoldersOnly = false;
		}

		public string GetNextSuggestion()
		{
			return this.PrepareSuggestionForReturn(this.suggestionProvider.GetNextSuggestion());
		}

		public string GetPreviousSuggestion()
		{
			return this.PrepareSuggestionForReturn(this.suggestionProvider.GetPreviousSuggestion());
		}

		private void PrepareSuggestionsIfRequired(string argFolder, string argPattern)
		{
			this.Pattern = argPattern;
			this.LastProvidedSuggestion = this.suggestionBase + argPattern;
			this.Folder = argFolder;

			this.suggestionProvider.PrepareSuggestions(this.Folder, this.Pattern, this.SuggestFoldersOnly);
		}

		private string PrepareSuggestionForReturn(string argSuggestion)
		{
			string tmpResult = null;
			if (argSuggestion != null)
			{
				this.LastProvidedSuggestion = this.suggestionBase + argSuggestion;

				tmpResult = this.LastProvidedSuggestion;
			}

			return tmpResult;
		}

		public string LastProvidedSuggestion
		{
			get
			{
				return this.lastProvidedSuggestion;
			}
			private set
			{
				this.lastProvidedSuggestion = value;
			}
		}

		public string Pattern
		{
			get
			{
				return this.pattern;
			}
			private set
			{
				this.pattern = value;
			}
		}

		private string Folder
		{
			get
			{
				return this.folder;
			}
			set
			{
				this.folder = value;
			}
		}

		private bool IsUpdated
		{
			get
			{
				return this.isUpdated;
			}
			set
			{
				this.isUpdated = value;
			}
		}

		private bool SuggestFoldersOnly
		{
			get
			{
				return this.suggestFoldersOnly;
			}
			set
			{
				this.suggestFoldersOnly = value;
			}
		}
	}
}
